/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: device api
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2022-05-27     JasonHu           Init
 */

#ifndef __NXOS_DEVICE_H__
#define __NXOS_DEVICE_H__

#include <nxos/xbook.h>
#include <nxos/process.h>
#include <nxos/list.h>
#include <nxos/hub.h>

#ifdef __cplusplus
extern "C" {
#endif

#define NX_DEVICE_NAME_LEN 32

/* device driver flags */
#define NX_DEVICE_OPEN_NEW_ONE  0x01 /* Every time NX_DeviceOpen is called, the open operation of ops will be called */

enum NX_DeviceType
{
    NX_DEVICE_TYPE_UNKNOWN = 0,
    NX_DEVICE_TYPE_BLOCK,
    NX_DEVICE_TYPE_CHAR,
    NX_DEVICE_TYPE_NET,
    NX_DEVICE_TYPE_UART,
    NX_DEVICE_TYPE_VIRT,
    NX_DEVICE_TYPE_SOUND,
    NX_DEVICE_TYPE_SCREEN,
    NX_DEVICE_TYPE_INPUT,
    NX_DEVICE_TYPE_IRQ,
    NX_DEVICE_TYPE_NR, /* device type number */
};
typedef enum NX_DeviceType NX_DeviceType;

#define NX_POLL_READ   0x01
#define NX_POLL_WRITE  0x02

typedef struct NX_PollState
{
    NX_Solt solt;
    NX_U32 inmask; /* input poll mask */
    NX_U32 outmask; /* output poll mask */
} NX_PollState;

struct NX_Device;

/* device operation set */
struct NX_DriverOps
{
    NX_Error (*open)(struct NX_Device *device, NX_U32 flags);
    NX_Error (*close)(struct NX_Device *device);
    NX_Error (*read)(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen);
    NX_Error (*write)(struct NX_Device *device, void *buf, NX_Offset off, NX_Size len, NX_Size *outLen);
    NX_Error (*control)(struct NX_Device *device, NX_U32 cmd, void *arg);
    NX_Error (*mappable)(struct NX_Device *device, NX_Size length, NX_U32 prot, NX_Addr * outPhyAddr);
    NX_Error (*poll)(struct NX_Device *device, NX_PollState * pState);
};
typedef struct NX_DriverOps NX_DriverOps;

typedef struct NX_Driver
{
    NX_List deviceListHead;
    NX_DeviceType type;
    char name[NX_DEVICE_NAME_LEN];
    NX_DriverOps *ops;
    NX_U32 flags;
    void *extension;
} NX_Driver;

typedef struct NX_Device
{
    NX_List list; /* device list */    
    NX_Driver *driver;
    char name[NX_DEVICE_NAME_LEN];
    void *extension;
} NX_Device;

struct NX_DeviceInfo
{
    char name[NX_DEVICE_NAME_LEN];
    NX_U32 mode;
    NX_DeviceType type;
};
typedef struct NX_DeviceInfo NX_DeviceInfo;

NX_Solt NX_DeviceOpen(const char * name, NX_U32 flags);
NX_Size NX_DeviceRead(NX_Solt solt, void *buf, NX_Offset off, NX_Size len);
NX_Size NX_DeviceWrite(NX_Solt solt, void *buf, NX_Offset off, NX_Size len);
NX_Error NX_DeviceControl(NX_Solt solt, NX_U32 cmd, void *arg);
#define NX_DeviceClose(solt) NX_SoltClose(solt)
void * NX_DeviceMap(NX_Solt solt, NX_Size length, NX_U32 prot);
NX_Error NX_PollWait(NX_Solt * soltTable, NX_Size maxSoltCount, int timeout, NX_PollState * pState);

NX_Driver *NX_DriverCreate(const char *name, NX_DeviceType type, NX_U32 flags, NX_DriverOps *ops);
NX_Error NX_DriverDestroy(NX_Driver *driver);

NX_Solt NX_DriverRegister(NX_Driver *driver);
#define NX_DriverUnregister(solt) NX_SoltClose(solt)

NX_Error NX_DriverAttachDevice(NX_Driver *driver, const char *name, NX_Device **outDevice);
NX_Error NX_DriverDetachDevice(NX_Driver *driver, const char *name);

#define NX_DriverRemapBuf(addr, size) NX_HubTranslate(addr, size)

NX_Error NX_DriverRun(NX_Solt driverSolt, NX_Driver * driver);

NX_Error NX_DeviceProbe(const char *name, NX_DeviceInfo *devinfo);
NX_Error NX_DeviceEnum(NX_Offset offset, NX_DeviceInfo *devinfo);

#ifdef __cplusplus
}
#endif

#endif  /* __NXOS_DEVICE_H__ */
